/**
 * LMX2592: TI-LMX2592-频率合成器,9.8GHz
 */
 
#include "share/std_err.h"
#include "share/utils.h"
#include "share/unios.h"
#include "lmx2592.h"

/*
 * LMX2592 的寄存器为 24 位，高位在前
 * bit[23:23]: R(1)/W(0) 标志
 * bit[22:16]: 7位寄存器地址
 * bit[15:0] : 16位寄存器值
 */
static std_err_t _regw(unidrv_lmx2592_t *dev, uint8_t regaddr, uint16_t regval) {
	uint8_t tx[3], rx[3];
    tx[0] = regaddr & 0x7F; // R(1)/W(0) 标志设置为 0 表示写寄存器
    tx[1] = (regval >> 8) & 0xFF;
    tx[2] = regval & 0xFF;
    
    dev->nss(0); //{{{
    std_err_t err = mcu_spi_trx(dev->spi, tx, rx, 3, NULL);
    dev->nss(1); //}}}
    return err;
}

static uint16_t _regr(unidrv_lmx2592_t *dev, uint8_t regaddr) {
	uint8_t tx[3], rx[3];
    tx[0] = regaddr | 0x80; // R(1)/W(0) 标志设置为 1 表示读寄存器
    tx[1] = 0xFF;
    tx[2] = 0xFF;
    
    dev->nss(0); //{{{
    mcu_spi_trx(dev->spi, tx, rx, 3, NULL);
    dev->nss(1); //}}}
    return (rx[1] << 8) | rx[2];
}

static std_err_t _spi_reg_write(unidrv_lmx2592_t *dev, uint32_t regval) {
	uint8_t tx[3], rx[3];
    tx[0] = (regval >> 16) & 0xFF;
    tx[1] = (regval >> 8 ) & 0xFF;
    tx[2] = (regval      ) & 0xFF;
    
    dev->nss(0); //{{{
    std_err_t err = mcu_spi_trx(dev->spi, tx, rx, 3, NULL);
    dev->nss(1); //}}}
    return err;
}

std_err_t unidrv_lmx2592_init(unidrv_lmx2592_t *dev, uint32_t regs[]) {
    int ret;
    uint16_t regv;
    
    // 先复位一下
    dev->ce(false); unios_us_delay(10000); dev->ce(true);
    
    // 设置 MUXOUT_SEL=0 以便把 MUXOUT 做为 SPI-MISO 信号使用，否则寄存器只能写不能读 !!!
    _regw(dev, 0x00, 0x2210); // LD_EN=1, FCAL_HPFD_ADJ=0, FCAL_LPFD_ADJ=0, ACAL_EN=1, FCAL_EN=0, MUXOUT_SEL=0, RESET=0, POWERDOWN=0
    
    // 检查芯片类型
    if(_regr(dev, 0x02) != 0x500) {
        return STD_ERR_INVALID_ID;
    }
    
	for(int i=0; regs[i] != LMX2592_REG_END; i++) {
        _spi_reg_write(dev, regs[i]);
		unios_us_delay(1000);
	}
    
    // 等待 PLL-Locked 方法1: 设置 MUXOUT_SEL=1 以便把 MUXOUT 做为 PLL-Locked 指示信号使用
    //regv = _regr(dev, 0x00); _regw(dev, 0x00, BitSet(regv, 2)); // MUXOUT_SEL=1
    //unios_wait_ms_until(ret, 10000, (dev->ld() == 1));
    //if(ret == 0) return STD_ERR_TIMEOUT;
    
    // 等待 PLL-Locked 方法2: 设置 R61.LD_TYPE=1 并读取 R68.rb_LD_VTUNE 做为 PLL-Locked 指示信号
    _regw(dev, 0x61, 1);
    unios_wait_ms_until(ret, 10000, ((_regr(dev, 0x68) >> 9) & 3) == 2);
    if(ret == 0) return STD_ERR_TIMEOUT;
    
	return STD_ERR_OK;
}
